<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
	<meta name="keywords" content="Dubbo,Seata,Consistency" />
	<meta name="description" content="This article will introduce you how to use Seata to ensure consistency between Dubbo Microservices." />
	<!-- 网页标签标题 -->
	<title>How to use Seata to ensure consistency between Dubbo Microservices</title>
  <link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
	<link rel="stylesheet" href="/build/blogDetail.css" />
</head>
<body>
	<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>How to use Seata to ensure consistency between Dubbo Microservices</h1>
<h2>Use case</h2>
<p>A business logic for user purchasing commodities. The whole business logic is powered by 3 microservices:</p>
<ul>
<li>Storage service: deduct storage count on given commodity.</li>
<li>Order service: create order according to purchase request.</li>
<li>Account service: debit the balance of user's account.</li>
</ul>
<h3>Architecture</h3>
<p><img src="/img/blog/seata/seata-1.png" alt="Architecture"></p>
<h3>StorageService</h3>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{

    <span class="hljs-comment">/**
     * deduct storage count
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
}
</code></pre>
<h3>OrderService</h3>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{

    <span class="hljs-comment">/**
     * create order
     */</span>
    <span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
}
</code></pre>
<h3>AccountService</h3>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{

    <span class="hljs-comment">/**
     * debit balance of user's account
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
}
</code></pre>
<h3>Main business logic</h3>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{

    <span class="hljs-keyword">private</span> StorageService storageService;

    <span class="hljs-keyword">private</span> OrderService orderService;

    <span class="hljs-comment">/**
     * purchase
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{

        storageService.deduct(commodityCode, orderCount);

        orderService.create(userId, commodityCode, orderCount);
    }
}
</code></pre>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StorageServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StorageService</span> </span>{

  <span class="hljs-keyword">private</span> StorageDAO storageDAO;
  
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span> </span>{
        Storage storage = <span class="hljs-keyword">new</span> Storage();
        storage.setCount(count);
        storage.setCommodityCode(commodityCode);
        storageDAO.update(storage);
    }
}
</code></pre>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{

    <span class="hljs-keyword">private</span> OrderDAO orderDAO;

    <span class="hljs-keyword">private</span> AccountService accountService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{

        <span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);

        accountService.debit(userId, orderMoney);

        Order order = <span class="hljs-keyword">new</span> Order();
        order.userId = userId;
        order.commodityCode = commodityCode;
        order.count = orderCount;
        order.money = orderMoney;

        <span class="hljs-keyword">return</span> orderDAO.insert(order);
    }
}
</code></pre>
<h2>Distributed Transaction Solution with Seata</h2>
<p><img src="/img/blog/seata/seata-2.png" alt="undefined"></p>
<p>We just need an annotation <code>@GlobalTransactional</code> on business method:</p>
<pre><code class="language-java">
    <span class="hljs-meta">@GlobalTransactional</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
        ......
    }
</code></pre>
<h2>Example powered by Dubbo + Seata</h2>
<h3>Step 1: Setup database</h3>
<ul>
<li>Requirement: MySQL with InnoDB engine.</li>
</ul>
<p><strong>Note:</strong> In fact, there should be 3 database for the 3 services in the example use case. However, we can just create one database and configure 3 data sources for simple.</p>
<p>Modify Spring XML with the database URL/username/password you just created.</p>
<p>dubbo-account-service.xml
dubbo-order-service.xml
dubbo-storage-service.xml</p>
<pre><code class="language-xml">    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /&gt;</span>
</code></pre>
<h3>Step 2: Create UNDO_LOG table for Seata</h3>
<p><code>UNDO_LOG</code> table is required by Seata AT mode.</p>
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
  <span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
  PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
  <span class="hljs-keyword">KEY</span> <span class="hljs-string">`idx_unionkey`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">159</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8
</code></pre>
<h3>Step 3: Create tables for example business</h3>
<pre><code class="language-sql">
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
  <span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
  PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
  <span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;


<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
  <span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
  <span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
  PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;


<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
  <span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
  <span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
  PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
</code></pre>
<h3>Step 4: Start Seata-Server</h3>
<ul>
<li>Download server <a href="https://github.com/seata/seata/releases">package</a>, unzip it.</li>
<li>Start Seata-Server</li>
</ul>
<pre><code class="language-shell">sh seata-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA

e.g.

sh seata-server.sh 8091 /home/admin/seata/data/
</code></pre>
<h3>Step 5: Run example</h3>
<ul>
<li>Start AccountService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboAccountServiceStarter.java">DubboAccountServiceStarter</a>).</li>
<li>Start StorageService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboStorageServiceStarter.java">DubboStorageServiceStarter</a>).</li>
<li>Start OrderService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboOrderServiceStarter.java">DubboOrderServiceStarter</a>).</li>
<li>Run BusinessService for test (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboBusinessTester.java">DubboBusinessTester</a>).</li>
</ul>
<h3>Related projects</h3>
<ul>
<li>seata:          <a href="https://github.com/seata/seata/">https://github.com/seata/seata/</a></li>
<li>seata-samples : <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
</ul>
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
	<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
	<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
	<script>
		window.rootPath = '';
  </script>
	<script src="/build/blogDetail.js"></script>
	<script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
    </script>
</body>
</html>
